/************************************************************
 * Project Name         [Thinking_In_Java]
 * File Name            [MathCalculator.java]
 * Creation Date        [10-Jul-2014]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ************************************************************/
package pkg_01_console_app.calculator;

import java.math.BigDecimal;

/**
 * 该类封装了控制台计算器使用到的全部数学运算功能, 包括:<br>
 * 整数与浮点数的加法运算的实现<br>
 * 整数与浮点数的减法运算的实现<br>
 * 整数与浮点数的乘法运算的实现<br>
 * 整数与浮点数的除法运算的实现<br>
 * 阶乘的实现<br>
 * 打印指定项数的斐波那契数列<br>
 * 十六进制与十进制的相互转换等
 * 
 * @author 不落的太阳(Sean Yang)
 * @version 1.0
 * @since JDK 6
 * 
 */
public class MathCalculator {

	/**
	 * 该方法用于两个整数相加
	 * 
	 * @param a
	 * @param b
	 * @return 以整数形式返回两个数的和
	 */
	public static int add(int a, int b) {
		return a + b;
	}

	/**
	 * 该方法用于两个小数相加
	 * 
	 * @param a
	 * @param b
	 * @return 以小数形式返回两个数的和
	 */
	public static double add(double a, double b) {
		return a + b;
	}

	/**
	 * 该方法用于两个整数相减
	 * 
	 * @param a
	 * @param b
	 * @return 以整数形式返回两个数的差
	 */
	public static int substract(int a, int b) {
		return a - b;
	}

	/**
	 * 该方法用于两个小数相减
	 * 
	 * @param a
	 * @param b
	 * @return 以小数形式返回两个数的差
	 */
	public static double substract(double a, double b) {
		return new BigDecimal(a + "").subtract(new BigDecimal(b + ""))
				.doubleValue();
	}

	/**
	 * 该方法用于两个整数相乘
	 * 
	 * @param a
	 * @param b
	 * @return 以整数形式返回两个数的积
	 */
	public static int multiply(int a, int b) {
		return a * b;
	}

	/**
	 * 该方法用于两个小数相乘
	 * 
	 * @param a
	 * @param b
	 * @return 以小数形式返回两个数的积.
	 */
	public static double multiply(double a, double b) {
		return a * b;
	}

	/**
	 * 该方法用于两个整数相除
	 * 
	 * @param a
	 * @param b
	 * @return 以整数形式返回两个数的商. 如果不能除尽, 以小数点后一位四舍五入返回结果
	 */
	public static int divide(int a, int b) {
		BigDecimal result = new BigDecimal(a / b); // 利用大数类的setScale方法进行进行结果返回
		return result.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
	}

	/**
	 * 该方法用于两个小数相除
	 * 
	 * @param a
	 * @param b
	 * @return 以小数形式返回两个数的商
	 */
	public static double divide(double a, double b) {
		return a / b;
	}

	/**
	 * 返回给定数的阶乘值
	 * 
	 * @param a
	 * @return 返回给定数的阶乘值
	 */
	public static long factorial(int a) {
		long result = 1; // 累乘结果的暂存变量.
		for (int i = 2; i <= a; i++) { // 从2-a进行循环累乘.
			result *= i;
		}
		return result; // 将累乘结果返回.
	}

	/**
	 * 打印斐波那契数列的前a项 斐波那契数列是指这样的一个数列: 1, 1, 2, 3, 5, 8, 13, 21...
	 * 
	 * 这个数列从第三项开始, 每一项都等于前两项之和. 通项可以表示为: f(n+1)=f(n)+f(n-1)
	 * 
	 * 该方法可以有两种方法实现, 一种是用循环+保存变量的方式实现, 另一种是使用循环+递归的方式实现
	 */
	public static void fibonacciVariable(int a) {
		// 使用保存变量的方式打印斐波那契数列
		int current; // 当前项
		int prev = 1; // 前一项
		int pprev = 1; // 前两项
		System.out.print("1,1");
		for (int i = 3; i <= a; i++, pprev = prev, prev = current) {
			current = prev + pprev;
			System.out.print("," + current);
		}
	}

	public static void fibonacciRecursion(int a) {
		// 调用getFibonacciAt()方法递归打印斐波那契数列
		for (int i = 1; i < a; i++) {
			System.out.print(getFibonacciAt(i) + ",");
		}
		System.out.println(getFibonacciAt(a));
	}

	/**
	 * 得到斐波那契数列第index项的值. 该方法使用递归实现
	 * 
	 * @param index
	 *            给定的参数, 表明斐波那契数列的第几项
	 * @return 返回一个整数, 表示斐波那契数列第index项的值
	 */
	public static int getFibonacciAt(int index) {
		if (index < 1)
			return -1; // 如果给定的参数不是正整数, 返回-1
		if (index == 1 || index == 2)
			return 1; // 如果给定的参数是前两项, 返回1

		// 进行递归, 得到第index项的值
		return getFibonacciAt(index - 1) + getFibonacciAt(index - 2);
	}

	/**
	 * 给定一个十六进制数, 得到十进制的结果
	 * 
	 * @param hex
	 * @return 返回给定十六进制数的十进制结果
	 */
	public static int toDec(String hex) throws NumberFormatException {
		return Integer.parseInt(hex, 16);
	}

	/**
	 * 给定一个十进制数, 得到十六进制的结果
	 * 
	 * @param dec
	 * @return 返回给定十进制数的十六进制结果
	 */
	public static String toHex(int dec) {
		return Integer.toHexString(dec);
	}

}
